using Newtonsoft.Json;
using Quartz;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.ScheduleJob.Manager;
using T.FAS.Runtime.ScheduleJob.SPI;

namespace T.FAS.Runtime.ScheduleJob.Service
{
    /// <summary>
    /// 公共的任务运行监听器
    /// </summary>
    public class BasicScheduleJobListener : IJobListener
    {
        public string Name => "TScheduleJobListner";
        public BasicScheduleJobListener()
        {
            new TaskFactory().StartNew(StartMonitorRunning).ContinueWith(RestartMonitorRunningTask);
        }

        /// <summary>
        /// 任务被取消
        /// </summary>
        /// <param name="context"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default)
        {
            IScheduleJobStateNotifier notifier = null;
            var data = context.MergedJobDataMap;
            ScheduleJobExecContext jContext = null;

            try
            {
                var jContextContent = data.GetString(ScheduleJobRTPConst.DefaultJobContextDataKey);
                jContext = JsonConvert.DeserializeObject<ScheduleJobExecContext>(jContextContent);
                if (jContext == null)
                    throw new FasException(ScheduleJobRTPExceptionCode.ScheduleJobRTPNullArgument, CommonStringClassService.BasicScheduleJobListener_JobExecutionContextCannotBeNull);

                notifier = new ScheduleJobStateNoticeFactory().GetNotifier(jContext);

                var noticeData = new ScheduleJobStateNoticeData()
                {
                    InstanceID = jContext.Instance.ID,
                    JobState = JobExecuteState.Pause,
                    JobResult = JobExecuteResult.None,
                    Message = $"{jContext.GetDescription()}在{DateTime.Now}被挂起"
                };
                return Task.Factory.StartNew(()=>
                {
                    notifier.Notice(jContext, noticeData);
                });
            }
            catch (Exception ex)
            {
                throw new FasException(ScheduleJobRTPExceptionCode.ScheduleJobExecuteError, string.Format(CommonStringClassService.BasicScheduleJobListener_JobExecutionVetoed1,ex.ToString()));
            }
        }
        /// <summary>
        /// 任务将要被调度执行
        /// </summary>
        /// <param name="context"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default)
        {
            IScheduleJobStateNotifier notifier = null;
            var data = context.MergedJobDataMap;
            ScheduleJobExecContext jContext = null;

            try
            {
                var jContextContent = data.GetString(ScheduleJobRTPConst.DefaultJobContextDataKey);
                jContext = JsonConvert.DeserializeObject<ScheduleJobExecContext>(jContextContent);
                if (jContext == null)
                    throw new FasException(ScheduleJobRTPExceptionCode.ScheduleJobRTPNullArgument, CommonStringClassService.BasicScheduleJobListener_JobExecutionContextCannotBeNull);

                notifier = new ScheduleJobStateNoticeFactory().GetNotifier(jContext);

                var noticeData = new ScheduleJobStateNoticeData()
                {
                    InstanceID = jContext.Instance.ID,
                    JobState = JobExecuteState.Executing,
                    JobResult = JobExecuteResult.None,
                    StartTime = DateTime.Now,
                    EndTime = ScheduleJobRTPUtil.GetDefaultTime()
                };

                return Task.Factory.StartNew(() =>
                {
                    notifier.Notice(jContext, noticeData);
                });
            }
            catch (Exception ex)
            {
                throw new FasException(ScheduleJobRTPExceptionCode.ScheduleJobExecuteError, string.Format(CommonStringClassService.BasicScheduleJobListener_JobToBeExecuted1,ex.ToString()));
            }
        }
        /// <summary>
        /// 任务已经被调度执行完成
        /// </summary>
        /// <param name="context"></param>
        /// <param name="jobException"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default)
        {
            IScheduleJobStateNotifier notifier = null;
            var data = context.MergedJobDataMap;
            ScheduleJobExecContext jContext = null;

            try
            {
                var jContextContent = data.GetString(ScheduleJobRTPConst.DefaultJobContextDataKey);
                jContext = JsonConvert.DeserializeObject<ScheduleJobExecContext>(jContextContent);
                if (jContext == null)
                    throw new FasException(ScheduleJobRTPExceptionCode.ScheduleJobRTPNullArgument, CommonStringClassService.BasicScheduleJobListener_JobExecutionContextCannotBeNull);

                notifier = new ScheduleJobStateNoticeFactory().GetNotifier(jContext);

                var noticeData = new ScheduleJobStateNoticeData()
                {
                    InstanceID = jContext.Instance.ID,
                    JobState = JobExecuteState.Executed,
                    JobResult = JobExecuteResult.Success,
                    EndTime = DateTime.Now
                };

                return Task.Factory.StartNew(() =>
                {
                    notifier.Notice(jContext, noticeData);
                });
            }
            catch (Exception ex)
            {
                try
                {
                    if (notifier != null && jContext != null)
                    {
                        var noticeData = new ScheduleJobStateNoticeData()
                        {
                            InstanceID = jContext.Instance.ID,
                            JobState = JobExecuteState.Executed,
                            JobResult = JobExecuteResult.Fail,
                            EndTime = DateTime.Now,
                            Message = $"{jContext.GetDescription()}执行失败，失败原因：{ex.ToString()}"
                        };
                        notifier.Notice(jContext, noticeData);
                    }
                }
                catch
                { }
                throw new FasException(ScheduleJobRTPExceptionCode.ScheduleJobExecuteError, string.Format(CommonStringClassService.BasicScheduleJobListener_JobWasExecuted1,ex.ToString()));
            }
        }

        private void StartMonitorRunning()
        {
            try
            {
                while (true)
                {
                    ScheduleJobRTPMonitor.MonitorScheduleJobEngineRunning();
                    Thread.Sleep(10 * 1000);
                }
            }
            catch
            { }
        }
        private void RestartMonitorRunningTask(Task t)
        {
            StartMonitorRunning();
        }
    }
}
